/**
 * Copyright [2019] [LiBo/Alex of copyright liboware@gmail.com ]
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hyts.fileupload.service;

import com.google.common.base.Preconditions;
import com.hyts.fileupload.bean.FileUploadProperties;
import com.hyts.fileupload.dao.FileInfoDao;
import com.hyts.fileupload.domain.FileInfoDomain;
import com.hyts.fileupload.domain.ResponseInfo;
import com.hyts.fileupload.error.FileUploadError;
import com.hyts.fileupload.utils.DateUtils;
import com.hyts.fileupload.utils.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Date;
import java.util.List;

/**
 * @project-name:coffice-toolbox
 * @package-name:com.hyts.fileupload.service
 * @author:LiBo/Alex
 * @create-date:2020-05-07 12:09
 * @copyright:libo-alex4java
 * @email:liboware@gmail.com
 * @description:
 */
@Slf4j
@Service
public class FileUploadService {

    @Autowired
    private FileInfoDao fileInfoDao;

    @Resource
    private FileUploadProperties fileUploadProperties;

    /**
     * 上传文件
     *
     * @param file
     * @return
     * @throws FileUploadError
     */
    @Transactional
    public ResponseInfo<?> upload(MultipartFile file) throws FileUploadError {
        //基础路径
        String basePath = fileUploadProperties.getBasePath();
        //获取文件保存路径 \20180608\113339\
        String folder = FileUtils.getFolder();
        // 获取前缀为"FL_" 长度为20 的文件名  FL_eUljOejPseMeDg86h.png
        String fileName = FileUtils.getFileName() + FileUtils.getFileNameSub(file.getOriginalFilename());
        try {
            // E:\springboot-upload\image\20180608\113339
            Path filePath = Files.createDirectories(Paths.get(basePath, folder));
            log.info("path01-->{}", filePath);
            //写入文件  E:\springboot-upload\image\20180608\113339\FL_eUljOejPseMeDg86h.png
            Path fullPath = Paths.get(basePath, folder, fileName);
            log.info("fullPath-->{}", fullPath);
            // E:\springboot-upload\image\20180608\113339\FL_eUljOejPseMeDg86h.png
            Files.write(fullPath, file.getBytes(), StandardOpenOption.CREATE);
            //保存文件信息
            FileInfoDomain fileInfo = new FileInfoDomain();
            fileInfo.setFileOriginName(file.getOriginalFilename());
            fileInfo.setFileType(file.getContentType());
            fileInfo.setSize(file.getSize());
            fileInfo.setMd5(FileUtils.md5File(fullPath.toString()));
            fileInfo.setFileName(fileName);
            fileInfo.setFilePath(filePath.toString());
            fileInfoDao.save(fileInfo);
        } catch (Exception e) {
            Path path = Paths.get(basePath, folder);
            log.error("写入文件异常,删除文件。。。。", e);
            try {
                Files.deleteIfExists(path);
            } catch (IOException e1) {
                log.error("删除清除文件失败!",e1);
            }
            return ResponseInfo.error(e.getMessage());
        }
        return ResponseInfo.success("上传成功");
    }

    /**
     * 文件下载
     *
     * @param fileName
     * @param res
     * @throws FileUploadError
     * @throws UnsupportedEncodingException
     */
    public void downloadFile(String fileName, HttpServletResponse res) throws FileUploadError, UnsupportedEncodingException {
        // 文件名称不允许为空!
        if (fileName == null) {
            throw new FileUploadError("1001", "文件名不能为空");
        }
        // 通过文件名查找文件信息
        FileInfoDomain fileInfo = fileInfoDao.findByFileName(fileName);
        log.info("fileInfo-->{}", fileInfo);
        if (fileInfo == null) {
            throw new FileUploadError("2001", "文件名不存在");
        }
        //设置响应头
        // 设置强制下载不打开
        res.setContentType("application/force-download");
        // 设置文件名
        res.addHeader("Content-Disposition", "attachment;fileName=" +
                new String(fileInfo.getFileOriginName().getBytes("gbk"), "iso8859-1"));
        res.setHeader("Context-Type", "application/xmsdownload");
        //判断文件是否存在
        File file = new File(Paths.get(fileInfo.getFilePath(), fileName).toString());
        if (file.exists()) {
            byte[] buffer = new byte[1024];
            try (
                 FileInputStream fis = new FileInputStream(file);
                 BufferedInputStream bis = new BufferedInputStream(fis);
                ){
                OutputStream os = res.getOutputStream();
                int i = bis.read(buffer);
                while (i != -1) {
                    os.write(buffer, 0, i);
                    i = bis.read(buffer);
                }
                log.info("下载成功");
            } catch (Exception e) {
                log.error("下载文件失败!",e);
                throw new FileUploadError("9999", e.getMessage());
            }
        }
    }

    /**
     * 文件查看
     */
    public FileInfoDomain getImage(String fileName) throws IOException {
        log.info("fileName-->{}", fileName);
        FileInfoDomain fileInfo = fileInfoDao.findByFileNameAndValid(fileName, true);
        if (fileInfo == null) {
            return null;
        }
        Path path = Paths.get(fileInfo.getFilePath(), fileInfo.getFileName());
        log.info("path-->{}", path);
        fileInfo.setContent(Files.newInputStream(path));
        return fileInfo;
    }

    /**
     * 根据资源id查询文件信息
     * @param resourceId
     * @return
     * @throws FileUploadError
     */
    public ResponseInfo<?> findFileList(String resourceId) throws FileUploadError {
        if (resourceId == null){
            throw new FileUploadError("1001","资源id不能为空");
        }
        // 根据资源id查询文件信息
        return ResponseInfo.success(fileInfoDao.findByResourceId(resourceId));
    }


    /**
     * 逻辑删除文件
     * @param fileName
     * @return
     * @throws FileUploadError
     */
    public ResponseInfo<?> deleteFile(String fileName) throws FileUploadError{
        if (fileName ==  null){
            throw new FileUploadError("1001","文件名不能为空");
        }
        FileInfoDomain fileInfo = fileInfoDao.findByFileName(fileName);
        if (fileInfo == null){
            throw new FileUploadError("2001","文件名:"+fileName+" 不存在");
        }
        // 逻辑删除文件
        fileInfo.setIsDelete(true);
        fileInfo.setDeleteTime(DateUtils.getDateString(new Date()));
        return ResponseInfo.success(fileInfo);
    }


    /**
     * 每天执行一次,清除无效图片
     */
    @Scheduled(cron = "0 0 0 1/1 * ? ")
    public void deleteValidFalse() {
        //定时删除无效图片信息
        List<FileInfoDomain> fileInfos = fileInfoDao.findByValid(false);
        fileInfoDao.deleteAll(fileInfos);
        log.info("本次删除数据:{}",fileInfos);
    }

}
